package qhLoading 
{
	import flash.events.Event;
	import flash.events.ProgressEvent;
	import flash.utils.Dictionary;
	import qhLoading.manager.ResourceManager;
	import qhLoading.info.ResourceInfo;
	import core.Caller;
	import qhLoading.loaders.BaseLoader;
	import pool.ObjectPool;
	/**
	 * ...
	 * @author gcxk721
	 */
	public class QhLoaderManager 
	{
		
		private var _completeCaller:Caller;
        private var _progressCaller:Caller;
        private var _errorCaller:Caller;
        public var maxQueue:int = 8;
        private var _queueMap:Dictionary;
        private var _currentCount:int = 0;
        private var _queueArray:Array;
        private var _highQueue:Array;
        private static var _instance:QhLoaderManager = new QhLoaderManager();

        public function QhLoaderManager()
        {
            if (_instance != null)
            {
                throw new Error("only init single instance");
            }
            this._queueArray = [];
            this._highQueue = [];
            this._completeCaller = new Caller();
            this._progressCaller = new Caller();
            this._errorCaller = new Caller();
        }

        public function load(name : String, onComplete : Function, priority : int = 3, data : Object = null, onProgress : Function = null, onError : Function = null) : void
        {
            var info : ResourceInfo = ResourceManager.getInfoByName(name);
            if (info == null)
            {
               //没有该文件
                if (onError is Function)
                {
                    onError(data);
                }
                return;
            }
			info.priority = priority;
            this.loadInfo(info, onComplete, priority, data, onProgress, onError);
        }

        public function loadInfo(info : ResourceInfo, onComplete : Function, priority : int = 3, data : Object = null, onProgress : Function = null, onError : Function = null) : void
        {
			if (data != null)
			{
				info.extData = data;	
			}
            if (info.isLoaded)
            {
                onComplete(info);
                info.addReference();
                return;
            }
			this._completeCaller.addCall(info.name, onComplete);
			if (onProgress is Function)
			{
				this._progressCaller.addCall(info.name, onProgress);
			}
			if (onError is Function)
			{
				this._errorCaller.addCall(info.name, onError);
			}
			if (!info.isLoading)
			{
				this.addLoader(info, priority);
			}
        }

        private function loadResource(info : ResourceInfo) : Boolean
        {
            var loaderCls : Class = null;
            var baseLoader : BaseLoader = null;
            if (this._currentCount < this.maxQueue)
            {
                loaderCls = FileType.getLoaderByType(info.type);
                if (loaderCls)
                {
                    baseLoader = ObjectPool.getObject(loaderCls) as BaseLoader;
                    baseLoader.addEventListener(Event.COMPLETE, this.onCompleteHandler);
                    baseLoader.addEventListener(ProgressEvent.PROGRESS, this.onProgressHandler);
                    baseLoader.addEventListener(LoaderErrorEvent.LoaderError, this.onIOErrorHandler);
                    baseLoader.load(info.path, info);
					_currentCount++;
                    info.isLoading = true;
                }
                else
                {
                    throw new Error("未知的文件类型");
                }
                return true;
            }
            return false;
        }

        private function addLoader(info : ResourceInfo, priority:int = 3) : void
        {
            if (!loadResource(info))
            {
                this.addQueue(info, priority);
                info.isLoading = true;
            }
        }

        private function addQueue(info : ResourceInfo, priority:int = 0) : void
        {
            if (priority >= 3)
            {
                this._queueArray.push(info);
            }
            else if (priority == 0)
            {
                this._highQueue.unshift(info);
            }
            else if (priority == 1)
            {
                this._highQueue.push(info);
            }
            else if (priority == 2)
            {
                this._queueArray.unshift(info);
            }
        }

        private function shiftQueue() : ResourceInfo
        {
            if (this._highQueue.length > 0)
            {
                return this._highQueue.shift() as ResourceInfo;
            }
            if (this._queueArray.length > 0)
            {
                return this._queueArray.shift() as ResourceInfo;
            }
            return null;
        }

        private function onCompleteHandler(event : Event) : void
        {
            _currentCount--;
            var baseLoader : BaseLoader = event.target as BaseLoader;
            baseLoader.removeEventListener(Event.COMPLETE, this.onCompleteHandler);
            baseLoader.removeEventListener(ProgressEvent.PROGRESS, this.onProgressHandler);
            baseLoader.removeEventListener(LoaderErrorEvent.LoaderError, this.onIOErrorHandler);
            if (baseLoader.resourceInfo)
            {
                baseLoader.resourceInfo.addReference();
                this._completeCaller.call(baseLoader.resourceInfo.name, baseLoader.resourceInfo);
                this._completeCaller.removeCallByType(baseLoader.resourceInfo.name);
                this._progressCaller.removeCallByType(baseLoader.resourceInfo.name);
                this._errorCaller.removeCallByType(baseLoader.resourceInfo.name);
            }
            baseLoader.dispose();
            ObjectPool.disposeObject(baseLoader);
            this.loadNext();
        }

        private function loadNext() : void
        {
            if (this._highQueue.length > 0)
            {
                if (this.loadResource(this._highQueue[0] as ResourceInfo))
                {
                    this._highQueue.shift();
                }
            }
            else if (this._queueArray.length > 0)
            {
                if (this.loadResource(this._queueArray[0] as ResourceInfo))
                {
                    this._queueArray.shift();
                }
            }
        }

        private function onProgressHandler(event : ProgressEvent) : void
        {
            var baseLoader:BaseLoader = event.target as BaseLoader;
            if (baseLoader.resourceInfo)
            {
                this._progressCaller.call(baseLoader.resourceInfo.name, event);
            }
        }

        private function onIOErrorHandler(event:LoaderErrorEvent) : void
        {
            _currentCount--;
            var baseLoader:BaseLoader = event.target as BaseLoader;
            if (baseLoader.resourceInfo)
            {
                baseLoader.resourceInfo.path = baseLoader.resourceInfo.path + "_1";
                baseLoader.resourceInfo.dispose();
                this._errorCaller.call(baseLoader.resourceInfo.name, event);
                this._completeCaller.removeCallByType(baseLoader.resourceInfo.name);
                this._progressCaller.removeCallByType(baseLoader.resourceInfo.name);
                this._errorCaller.removeCallByType(baseLoader.resourceInfo.name);
            }
			baseLoader.dispose();
            ObjectPool.disposeObject(baseLoader);
            this.loadNext();
        }

        public function disposeFile(name:String) : void
        {
            var info : ResourceInfo = ResourceManager.getInfoByName(name);
            if (info != null)
            {
                info.dispose();
            }
        }

        public static function get instance() : QhLoaderManager
        {
            return _instance;
        }
		
	}

}